﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace wpfTool
{
    /// <summary>
    /// Interaction logic for ShaderWidget.xaml
    /// </summary>
    public partial class ShaderWidget : UserControl
    {
        int gridHeight = 20;
        ShaderBase shader = null;
        PipelineView pipelineView = null;
        Point currPos;

        SortedDictionary<int, Rectangle> srcPortList = null;
        SortedDictionary<int, Rectangle> dstPortList = null;

        internal int numOfRegistedAttachLines = 0;

        public SortedDictionary<int, Rectangle> SrcPortList
        {
            get 
            {
                if (srcPortList == null)
                    srcPortList = new SortedDictionary<int, Rectangle>();
                   
                return srcPortList; 
            }
        }
        public SortedDictionary<int, Rectangle> DstPortList
        {
            get 
            {
                if (dstPortList == null)
                    dstPortList = new SortedDictionary<int, Rectangle>();
                return dstPortList; 
            }
        }

        public Point getSrcPortCoord(int index)
        {
            Point pos = new Point();
            pos.X = X;

            pos.Y = Y + fileName.Height + index * GridHeight / 2;

            return pos;
        }

        public Point getDstPortCoord(int index)
        {
            Point pos = new Point();
            pos.X = X + this.Width;

            pos.Y = Y + fileName.Height + index * GridHeight / 2;

            return pos;
        }

        public ShaderBase Shader
        {
            get { return shader; }
        }

        public double Y
        {
            get { return Canvas.GetTop(this); }
            set { Canvas.SetTop(this, value); }
        }
        public double X
        {
            get { return Canvas.GetLeft(this); }
            set { Canvas.SetLeft(this, value); }
        }

        public int GridHeight
        {
            get { return gridHeight;}
            set { gridHeight = value;}
        }

        public int GridElementHeight
        {
            get { return gridHeight - 5;}
        }

        // should never be used!
        public ShaderWidget()
        {
            InitializeComponent();

            throw new System.Exception("Wrong Ctor!");
        }

        public ShaderWidget(ShaderBase shader, PipelineView parentPipeline)
        {
            InitializeComponent();

            this.shader = shader;
            this.pipelineView = parentPipeline;

            registerEvents();
            this.assemblePortsGrid(shader);
        }

        static ImageSource bitmap2bitmapsource(System.Drawing.Bitmap src)
        {
            IntPtr p = src.GetHbitmap();
            BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(p,
                IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());

            return bitmapSource;
        }

        public void updatePreview(System.Drawing.Bitmap bmp)
        {
            previewPort.Source = ShaderWidget.bitmap2bitmapsource(bmp);
            prograssBar.Value = 0.0f;

            adjustWidgetHeight();
        }

        public void updateProgressBar(float percentage)
        {
            if (percentage < 1.0f)
                prograssBar.Value = percentage;
            else
                prograssBar.Value = 0.0f;
        }

        System.Windows.Media.Brush getColor(Type type)
        {
            if (type.Equals(typeof(float)))
                return System.Windows.Media.Brushes.Yellow;
            else if (type.Equals(typeof(System.Drawing.Bitmap)))
                return System.Windows.Media.Brushes.Red;
            else if (type.Equals(typeof(Array)))
                return System.Windows.Media.Brushes.Green;
            else if (type.Equals(typeof(string)))
                return System.Windows.Media.Brushes.Black;

            return Brushes.Pink;
        }

        void assemblePortsGrid(ShaderBase shader)
        {
            int curRowsI = 0;

            if(shader.InputPortsList != null)
                foreach (wpfTool.PortInfo pi in shader.InputPortsList)
                {
                    Label l = new Label();
                    l.Content = pi.portName;
                    l.Height = GridElementHeight;
                    l.Padding = new Thickness(1);
                    l.HorizontalAlignment = HorizontalAlignment.Left;
                    Grid.SetColumn(l, 1);
                    Grid.SetRow(l, curRowsI);
                    portsGrid.Children.Add(l);
     
                    Rectangle rect = new Rectangle();
                    rect.Fill = getColor(pi.type);
                    rect.Stroke = Brushes.Black;
                    rect.Height = GridElementHeight;
                    rect.Width = GridElementHeight;
                    rect.HorizontalAlignment = HorizontalAlignment.Left;
                    rect.MouseLeftButtonUp +=  new MouseButtonEventHandler(OnMouseLeftDst);
                    DstPortList[curRowsI] = rect;
                    Grid.SetColumn(rect, 0);
                    Grid.SetRow(rect, curRowsI);
                    portsGrid.Children.Add(rect);

                    ++curRowsI;
                }

            int curRowsO = 0;

            if(shader.OutputPortsList != null)
                foreach (wpfTool.PortInfo pi in shader.OutputPortsList)
                {
                    Label l = new Label();
                    l.Content = pi.portName;
                    l.Height = GridElementHeight;
                    l.Padding = new Thickness(1);
                    l.HorizontalAlignment = HorizontalAlignment.Right;
                    Grid.SetColumn(l, 2);
                    Grid.SetRow(l, curRowsO);
                    portsGrid.Children.Add(l);

                    Rectangle rect = new Rectangle();
                    rect.Fill = getColor(pi.type);
                    rect.Stroke = Brushes.Black;
                    rect.Height = GridElementHeight;
                    rect.Width = GridElementHeight;
                    rect.HorizontalAlignment = HorizontalAlignment.Right;
                    rect.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseLeftSrc);
                    rect.MouseLeftButtonDown += new MouseButtonEventHandler(pipelineView.OnMouseButtonLeftDown);
                    SrcPortList[curRowsO] = rect;
                    Grid.SetColumn(rect, 3);
                    Grid.SetRow(rect, curRowsO);
                    portsGrid.Children.Add(rect);

                    ++curRowsO;
                }

            int numOfRows = Math.Max(curRowsI, curRowsO) + 1;
            RowDefinitionCollection rds = portsGrid.RowDefinitions;
            while (numOfRows > rds.Count)
            {
                RowDefinition rd = new RowDefinition();
                rd.Height = new System.Windows.GridLength(GridHeight);
                rds.Add(rd);
            }

            widgetTypeName.Content = shader.ShaderName;
        }


        void OnMouseLeftSrc(object sender, MouseButtonEventArgs e)
        {
            if (pipelineView.MainWindow.IsEditMode)
            {
                int rowIndex = Grid.GetRow(e.Source as UIElement);

                if (pipelineView.srcInfo == null)
                    pipelineView.srcInfo = new ShaderWidgetConnectionInfo(this, rowIndex);
            }
        }

        void OnMouseLeftDst(object sender, MouseButtonEventArgs e)
        {
            if (pipelineView.MainWindow.IsEditMode)
            {
                int rowIndex = Grid.GetRow(e.Source as UIElement);

                if (pipelineView.dstInfo == null)
                    pipelineView.dstInfo = new ShaderWidgetConnectionInfo(this, rowIndex);
            }
        }


        void registerEvents()
        {
            shader.ShaderUpdated += new Window1.ShaderUpdatedHandler(updatePreview);
            shader.ShaderProgressEvent += new Window1.ShaderProgressEventHandler(updateProgressBar);

            this.MouseMove += new MouseEventHandler(ShaderWidget_MouseMove);
            this.MouseLeftButtonUp += new MouseButtonEventHandler(ShaderWidget_MouseLeftButtonUp);
            this.MouseLeftButtonDown += new MouseButtonEventHandler(ShaderWidget_MouseLeftButtonDown);
        }

        void ShaderWidget_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (!pipelineView.MainWindow.IsEditMode)
                this.BitmapEffect = new System.Windows.Media.Effects.DropShadowBitmapEffect();
        }

        void ShaderWidget_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (!pipelineView.MainWindow.IsEditMode)
            {
                currPos = e.GetPosition(pipelineView.canvas);
                this.BitmapEffect = null;
            }
            else
                ShaderWidgetGetFocus(Shader);
        }

        void ShaderWidget_MouseMove(object sender, MouseEventArgs e)
        {
            if (!pipelineView.MainWindow.IsEditMode)
            {
                if (e.LeftButton == MouseButtonState.Pressed)
                {
                    Point pos = new Point();
                    pos = e.GetPosition(pipelineView.canvas);

                    double deltaX = pos.X - currPos.X;
                    double deltaY = pos.Y - currPos.Y;

                    currPos = pos;

                    this.X += deltaX;
                    this.Y += deltaY;

                    if(numOfRegistedAttachLines > 0)
                        this.ShaderWidgetMove(this);
                }
            }
        }

        void adjustWidgetHeight()
        {
            double height = 0.0;

            height += fileName.Height;
            height += portsGrid.Height;
            height += previewPort.Height;
            height += prograssBar.Height;
            height += widgetTypeName.Height;

            this.Height = height;
        }

        public event Window1.ShaderWidgetMoveHandler ShaderWidgetMove;
        public event Window1.ShaderPropertyChangeHandler ShaderWidgetGetFocus;

    }
}
